/* 
    第一步：提炼函数 switch 部分
        1. 检查哪些变量会离开原来的作用域
        2. 关心其中会被修改的变量
            -- 这里只有一个变量会被修改，所以可以直接 return 
        3. 不管每次重构多么简单，修改后都要立刻运行测试
        4. 每次成功重构后都提交到本地
    第二步： 修改 amountFor()中的 thisAmount 为 result
        -- 永远将函数的返回值命名为 result，这样能一眼看出它的作用
    第三步：修改参数名称
        1. 修改 perf 名称为 aPerformance
            -- 使用动态语言时，加上类型名，一般使用不定冠词修饰它
        2. 修改 play 名称（移除参数）
            -- 由于 play 是由 aPerformance 计算出来的，所以没必要把它作为参数传入
            -- 可以在 amountFor 函数中重新计算得到 play，所以我们移除掉它
            -- 因为临时变量会使提炼函数变得复杂
    第四步：移除 play 参数
        1. 把用 aPerformance 计算 play 的方法提炼出来
        2. 移除 amountFor() 中的参数 play，在函数体内声明 const play = playFor(aPerformance);
        3. 替换 amountFor() 中的 play： 换成 playFor(aPerformance)
        4. 替换 statement 中的 play： 换成 playFor(perf)
    第五步：处理其它局部变量
        1. volumeCredits 是累加变量，值会随迭代改变，所以将其提炼到新函数中
        2. 把 volumeCreditsFor() 中的 let volumeCredits = 0； 的临时变量换成 result
        3. 移除 format
            -- format 是临时变量，这其实是鼓励你写长而复杂的函数
            -- 这里是一个典型的“将函数赋值给临时变量”，可以将其替换为一个明确声明的函数
            -- 给 format() 重命名
        4. 移除 volumeCredits
            -- 拆分循环
            -- 把 let volumeCredits = 0; 放到紧挨着 volumeCredits 累加循环的上方
            -- 以查询取代临时变量
        5. 移除 totalAmount
            -- 拆分循环
            -- 把 let totalAmount = 0; 放到紧挨着 totalAmount 累加循环的上方
            -- 以查询取代临时变量
*/
function statement(invoice, plays) {

    function amountFor(aPerformance){
        let result = 0;
        switch (playFor(aPerformance).type) {
            case "tragedy":
                result = 40000;
                if (aPerformance.audience > 30) {
                    result += 1000 * (aPerformance.audience - 30);
                }
                break;
            case "comedy":
                result = 3000;
                if (aPerformance.audience > 20) {
                    result += 1000 + 500 * (aPerformance.audience - 20);
                }
                break;
            default:
                throw new Error("unknown type:" + playFor(aPerformance).type);
        }
        return result;
    }

    
    function playFor(aPerformance){
        return plays[aPerformance.playID];
    }

    function volumeCreditsFor(aPerformance){
        let result = 0;
        result += Math.max(aPerformance.audience - 30, 0);
        if ("comedy" ===  playFor(aPerformance).type) {
            result += Math.floor(aPerformance.audience/5);
        }
        return result;
    }

    function usd(aNumber){
        return new Intl.NumberFormat("en-US", {
            style: "currency", currency: "USD",
            minimumFractionDigits: 2
        }).format(aNumber/100);
    }

    function totalVolumeCredits(){
        let result = 0;
        for (let perf of invoice.performance) {
            result += volumeCreditsFor(perf);
        }
        return result;
    }

    function totalAmount(){
        let result = 0;
        for (let perf of invoice.performance) {
            result += amountFor(perf);
        };
        return result;
    }

    let result = "Statement for " + invoice.customer + "\n";
    for (let perf of invoice.performance) {
        result += "-- " +  playFor(perf).name + ": " + usd(amountFor(perf)) + " (" + perf.audience + " seats)" + "\n";
    };

    result += "Amount owed id " + usd(totalAmount()) + "\n";
    result += "You earned " + totalVolumeCredits() + " credits";
    console.log(result);
    return result;
}

/****************************************** */
function readJson(fileName, callback) {
    var fs = require('fs');
    fs.readFile(fileName, 'utf-8', (err, data) => {
        if (err) {
            console.error(err);
        } else {
            callback(JSON.parse(data));
        }
    });
}

var invoice;
var play;
readJson("invoices.json", (myData) => {
    invoice = myData;
});
readJson("play.json", (myData) => {
    play = myData;
});
var timer = setInterval(() => {
    if (invoice) {
        clearInterval(timer);
        // console.log({ invoice });
        // console.log({ play });
        statement(invoice, play);
    }
}, 500);
